#include "PADSObject.h"
#include "d_Camera.h"
#include "Image.h"
#include <GL/gl.h>

float PADSNode::distToCamera(Vec3 vec)
{
	//float a = plane_normal[0], b = plane_normal[1], c = plane_normal[2];
	//float d = -a*cam_pos[0]-b*cam_pos[1]-c*cam_pos[2];
	//return (a*vec[0] + b*vec[1] + c*vec[2] + d)/sqrt(a*a+b*b+c*c);
	return sqrt((cam_pos[0]-vec[0])*(cam_pos[0]-vec[0]) + 
						(cam_pos[1]-vec[1])*(cam_pos[1]-vec[1]) +
						(cam_pos[2]-vec[2])*(cam_pos[2]-vec[2]));
}

void PADSNode::outputToFile(char *filename)
{
	unsigned char *rgb;
  float fx = 1, fy = 1;
  int x = bb_x, y = bb_y, w = bb_w, h = bb_h;

  printf("reading Image buffer\n");

  rgb=(unsigned char*)malloc(w*h*3);
  glPixelZoom(fx,fy);
  glPixelStoref (GL_PACK_ALIGNMENT, 1);
  glReadPixels (x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, (void *)(rgb));

  Image out_img(w, h);
  for (int i = h-1; i >=0; i-- ) {
    for (int j = 0; j < w; j++ ) {
      unsigned char r, g, b;
      r = rgb[(j*3)+(i*w*3)];
      g = rgb[(j*3)+(i*w*3)+1];
      b = rgb[(j*3)+(i*w*3)+2];
      out_img.SetRGB(j,i,r,g,b);
    }
  }
  delete rgb;
  out_img.Save(0, filename);
}

void PADSNode::extractBB(int sw, int sh)
{
	  unsigned char *rgb;
	  float fx = 1, fy = 1;
	  int x = 0, y = 0, w = sw, h = sh;
	  bool found_x = false, found_y = false, found_w = false, found_h = false;
	
	  rgb=(unsigned char*)malloc(w*h*3);

	  glPixelZoom(fx,fy);
	  glPixelStoref (GL_PACK_ALIGNMENT, 1);
	  glReadPixels (x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, (void *)(rgb));

	  for (int i = 0; i <=h-1; i++ ) {
		for (int j = 0; j < w; j++ ) {
		  if(!found_y)
			  if(rgb[(j*3)+(i*w*3)]==255)
			  {
				  found_y = true;
				  bb_y = i-1;
			  }
		}
	  }

	  for (int i = h-1; i >=0; i-- ) {
		for (int j = 0; j < w; j++ ) {
		  if(!found_h)
			  if(rgb[(j*3)+(i*w*3)+1]==255)
			  {
				  found_h = true;
				  bb_h = i-bb_y+1;
			  }
		}
	  }

	  for (int j = 0; j < w; j++ ) {
		for (int i = h-1; i >=0; i-- ) {
		  if(!found_x)
			  if(rgb[(j*3)+(i*w*3)]==255)
			  {
				  found_x = true;
				  bb_x = j-1;
			  }
		}
	  }

	  for (int j = w; j > 0; j-- ) {
		for (int i = h-1; i >=0; i-- ) {
		  if(!found_w)
			  if(rgb[(j*3)+(i*w*3)]==255)
			  {
				  found_w = true;
				  bb_w = j-bb_x+1;
			  }
		}
	  }
	  delete rgb;
}

PADSNode::PADSNode(VCGCamera *camera, Patch *p, ModelDisplay *instance, Mesh *minstance)
{
	float min_dist=10000000;
	float max_dist=0;
	char output[30];
	scr_w = instance->camera->getW();
	scr_h = instance->camera->getH();
	cam_pos = camera->vp;
	plane_normal = camera->za;
	for(FaceIter f=p->faces_patch_begin(); f!=p->faces_patch_end(); f++)
	 {
		 for(int i=0;i<3;i++)
		 {
			 float tmp_dist = distToCamera((*f)->vertex(i)->a.g);
			 if(tmp_dist < min_dist)
				 min_dist = tmp_dist;
			 if(tmp_dist > max_dist)
				 max_dist = tmp_dist;
		 }
	 }
	dist_plane = min_dist;
	plane_dx = max_dist-min_dist;
	d_Camera *cam = new d_Camera();

		cam->setDimensions(640,480);
		cam->setViewport(0,0,640,480);
		cam->setDirection(camera->za[0],camera->za[1],camera->za[2]);
		cam->setPerspective(camera->fov);
		cam->setUpDirection(camera->ya[0], camera->ya[1], camera->ya[2]);
		cam->setPosition(camera->vp[0], camera->vp[1], camera->vp[2]);

		cam->applyViewport();
		cam->applyPerspective();
		cam->applyModelview();

		glDisable(GL_LIGHTING);

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(0,0,0,1);
		instance->dont_draw = true;
		instance->redraw();
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(0,0,0,1);

		glBegin(GL_TRIANGLES);
			 for(FaceIter f=p->faces_patch_begin(); f!=p->faces_patch_end(); f++)
			 {			 
				 for(int i=0;i<3;i++)
				 {
					 glColor3f(1, 1, 1);
					 glNormal3d((*f)->vertex(i)->a.n[X], (*f)->vertex(i)->a.n[Y], (*f)->vertex(i)->a.n[Z]);
					 glVertex3d((*f)->vertex(i)->a.g[X], (*f)->vertex(i)->a.g[Y], (*f)->vertex(i)->a.g[Z]);
				 }
			 }
		glEnd();

		extractBB(640, 480);

		sprintf(output, "%i_CF.gif", p->get_index());
		//outputToFile(output);
		instance->redraw();
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(0,0,0,1);

		//This routine draws the position map
		glBegin(GL_TRIANGLES);
			 for(FaceIter f=p->faces_patch_begin(); f!=p->faces_patch_end(); f++)
			 {			 
				 for(int i=0;i<3;i++)
				 {
					 float color = (distToCamera((*f)->vertex(i)->a.g)-dist_plane)/plane_dx;
					 glColor3f(1, color, 0);//(float) bb_x / (float) scr_w, (float) bb_y / (float) scr_h);
					 glNormal3d((*f)->vertex(i)->a.n[X], (*f)->vertex(i)->a.n[Y], (*f)->vertex(i)->a.n[Z]);
					 glVertex3d((*f)->vertex(i)->a.g[X], (*f)->vertex(i)->a.g[Y], (*f)->vertex(i)->a.g[Z]);
				 }
			 }
		glEnd();

		instance->redraw();
		sprintf(output, "%i_P.gif", p->get_index());
		outputToFile(output);
		outputToFile(output);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(0,0,0,1);

		//this routine draws the normal map
		glBegin(GL_TRIANGLES);
			 for(FaceIter f=p->faces_patch_begin(); f!=p->faces_patch_end(); f++)
			 {			 
				 for(int i=0;i<3;i++)
				 {
					 glColor3f((*f)->vertex(i)->a.n[X]/2+.5, (*f)->vertex(i)->a.n[Y]/2+.5, (*f)->vertex(i)->a.n[Z]/2+.5);
					 glNormal3d((*f)->vertex(i)->a.n[X], (*f)->vertex(i)->a.n[Y], (*f)->vertex(i)->a.n[Z]);
					 glVertex3d((*f)->vertex(i)->a.g[X], (*f)->vertex(i)->a.g[Y], (*f)->vertex(i)->a.g[Z]);
				 }
			 }
		glEnd();

		instance->redraw();
		cam->resetPerspective();
		sprintf(output, "%i_N.gif", p->get_index());
		outputToFile(output);
		outputToFile(output);
		
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(0,0,0,1);

		//this routine draws the color map
		instance->drawPatch(p->get_index());

		instance->redraw();
		cam->resetPerspective();
		sprintf(output, "%i_C.gif", p->get_index());
		outputToFile(output);
		//outputToFile(output);
		//delete cam;

		instance->dont_draw = false;
}

PADSObject::PADSObject(Mesh *mesh)
{
	int num_patches = mesh->num_patches();
	patches = (PADSPatch *) malloc (num_patches*sizeof(PADSPatch));
	minstance = mesh;
	
}
